﻿#include "homewindow.h"
#include "ui_homewindow.h"
#include <QDateTime>
#include <QApplication>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QUrl>
#include "globalhelper.h"
#include "audiooptimizerdialog.h"
#include "recordsettingdialog.h"
#include "livesettingdialog.h"
#include "easylogging++.h"

#pragma execution_character_set("utf-8")
HomeWindow::HomeWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::HomeWindow)
{
    ui->setupUi(this);
    initUi();
}

HomeWindow::~HomeWindow()
{
    delete ui;
}

bool HomeWindow::start(std::string url)
{
    if(business_type_ == 0) {
        enable_record_ = ui->checkBoxRecord->isChecked();
    }
    bool ret = false;
    ret =  startLiveOrRecord(url);
    if(!ret) {
        QString tips;
        tips.sprintf("录制失败，请查看日志");
        emit sig_showTips(Toast::ERROR, tips);
        return false;
    }
    return true;
}

bool HomeWindow::stop()
{
    stopTimer();
    push_work_->DeInit();
    delete push_work_;
    push_work_ = nullptr;
    ui->previewWidget->StopPlay();
    ui->stopBtn->setEnabled(false);
    ui->startOrPauseBtn->setText("开始");
    return true;
}

int HomeWindow::OutputVideo(const Frame *frame)
{
    // 调用显示控件
    return ui->previewWidget->Draw(frame);
}

void HomeWindow::initUi()
{
    //加载样式
    QString qss = GlobalHelper::GetQssStr("://res/qss/homewindow.css");
    setStyleSheet(qss);
    ui->avLabel->setOpenExternalLinks(true);
    ui->avLabel->setText(tr("<a style='color: red; text-decoration: none' href = https://www.baidu.com>点击一下试一试"));
    ui->liveRadioButton->setCheckable(true);
    ui->stopBtn->setEnabled(false);
    ui->startOrPauseBtn->setEnabled(true);
    // 初始化直播是否同时录制
    int live_record = 0;
    GlobalHelper::GetLiveRecord(live_record);
    if(live_record == 1) {
        ui->checkBoxRecord->setChecked(true);
        enable_record_ = true;
    } else {
        ui->checkBoxRecord->setChecked(false);
        enable_record_ = false;
    }
    // 初始化获取业务类型
    GlobalHelper::GetBusinessesType(business_type_);
    if(business_type_ == 0) {
        enable_rtmp_live_ = true;
        ui->liveRadioButton->setChecked(true);
    }
    if(business_type_ == 1) {
        enable_record_ = true;
        ui->recRadioBtn->setChecked(true);
    }
    //初始化的时候当前时间为0
    do_updateTime(0);
    // toast提示不能直接在非ui线程显示，所以通过信号槽的方式触发提示
    // 自定义信号槽变量类型要注册，参考:https://blog.csdn.net/Larry_Yanan/article/details/127686354
    qRegisterMetaType<Toast::Level>("Toast::Level");
    connect(this, &HomeWindow::sig_showTips, this, &HomeWindow::on_showTips);
    //音频优化
    connect(ui->actionAudioOptimizer, &QAction::triggered, this, &HomeWindow::on_audioOptimizer);
    // 录制设置
    connect(ui->actionRecordSetting, &QAction::triggered, this, &HomeWindow::on_recordSetting);
    // 直播设置
    connect(ui->actionLiveSetting, &QAction::triggered, this, &HomeWindow::on_liveSetting);
    // 更新录制时间设置
    connect(this, &HomeWindow::sig_updateTime, this, &HomeWindow::on_updateTime);
}

bool HomeWindow::startLiveOrRecord(string url)
{
    // 直播业务且rtmp url为空
    if(url.empty() && business_type_ == 0) {
        emit sig_showTips(Toast::ERROR, "URL为NULL");
        return false;
    }
    if(push_work_) {
        stop();
    }
    // 设置属性
    Properties properties;
    //是否录制
    properties.SetProperty("enable_record", enable_record_);
    record_file_name_ = getRecordFileName();        // 获取录制文件名和路径
    properties.SetProperty("record_file_name", record_file_name_);
    // audio采集设备名称
    QString expect_mic_name;
    GlobalHelper::GetDefaultMicDevice(expect_mic_name); // 获取保存的默认设备
    QString act_mic_name = RecordSettingDialog::GetAudioDefaultMicDeviceName(expect_mic_name);
    if(act_mic_name.isEmpty()) {
        emit sig_showTips(Toast::ERROR, "没有找到麦克风设备");
        return false;
    }
    if(act_mic_name != expect_mic_name) {
        emit sig_showTips(Toast::WARN, "更换麦克风设备为:" + act_mic_name);
    }
    act_mic_name = "audio=" + act_mic_name;   //记得加上这个前缀
    properties.SetProperty("audio_device_name", act_mic_name.toStdString());
    int audio_ns = -1;
    GlobalHelper::GetAudioNs(audio_ns);
    properties.SetProperty("audio_ns",  audio_ns);
    int audio_agc = 0;
    GlobalHelper::GetAudioAgc(audio_agc);
    properties.SetProperty("audio_agc",  audio_agc);
    // video采集设备名称
    properties.SetProperty("video_device_name", "video=screen-capture-recorder");
    // 音频编码属性 设置采样格式，码率，声道数量  固定使用aac编码
    properties.SetProperty("audio_sample_rate", 48000);
    properties.SetProperty("audio_channels", 2);
    properties.SetProperty("audio_bitrate", 128 * 1024);
    // 桌面录制属性 分辨率、帧率、码率、像素格式  固定使用h264编码
    properties.SetProperty("desktop_x", 0);
    properties.SetProperty("desktop_y", 0);
    QDesktopWidget *qDesktopWidget = QApplication::desktop();
    QRect qrect1 = qDesktopWidget->screen(0)->rect();
    int desktop_width = qrect1.width();
    int desktop_height = qrect1.height();
    properties.SetProperty("desktop_width", desktop_width); //屏幕分辨率
    properties.SetProperty("desktop_height", desktop_height);  // 屏幕分辨率
    properties.SetProperty("desktop_pixel_format", AV_PIX_FMT_YUV420P);
    properties.SetProperty("desktop_fps", 25);//测试模式时和yuv文件的帧率一致
    // 视频编码属性 视频的分辨率和可以桌面采集不一样
    properties.SetProperty("video_bitrate",  3*1024 * 1024); // 设置码率
    // rtmp推流
    properties.SetProperty("enable_rtmp", enable_rtmp_live_);
    properties.SetProperty("rtmp_url", url.c_str());
    push_work_ = new PushWork();
    push_work_->AddVidePreviewCallback(std::bind(&HomeWindow::OutputVideo, this,
                                       std::placeholders::_1));
    if(push_work_->Init(properties) != RET_OK) {
        delete push_work_;
        push_work_ = nullptr;
        LogError("pushwork.Init failed");
        return false;
    }
    ui->previewWidget->StartPlay();
    ui->stopBtn->setEnabled(true);
    ui->startOrPauseBtn->setText("暂停");
    startTimer();
    return true;
}

string HomeWindow::getRecordFileName()
{
    QString file_dir;
    GlobalHelper::GetFileDir(file_dir);
    QDateTime time = QDateTime::currentDateTime();
    // 比如 20230513-161813-769.jpg
    QString dateTime = file_dir + "/" + time.toString("yyyyMMdd-hhmmss-zzz") + ".mp4";
    return dateTime.toStdString();
}

void HomeWindow::do_updateTime(long millisecond)
{
    int seconds;
    seconds = millisecond / 1000; // 将毫秒转为秒
    int hour = int(seconds / 3600);
    int min = int((seconds - hour * 3600) / 60);
    int sec = seconds % 60;
    //QString格式化arg前面自动补0
    QString str = QString("%1:%2:%3").arg(hour, 2, 10, QLatin1Char('0')).arg(min, 2, 10, QLatin1Char('0')).arg(sec, 2, 10, QLatin1Char('0'));
    ui->timeLablel->setText(str);
}

void HomeWindow::startTimer()
{
    if(timer_) {
        timer_->stop();
        delete timer_;
        timer_ = nullptr;
    }
    timer_ = new QTimer();
    timer_->setInterval(1000);  // 1秒触发一次
    connect(timer_, SIGNAL(timeout()), this, SLOT(on_timeOut()));
    timer_->start();
}

void HomeWindow::stopTimer()
{
    if(timer_) {
        timer_->stop();
        delete timer_;
        timer_ = nullptr;
    }
}

void HomeWindow::on_audioOptimizer()
{
    // 音频优化设置 主要是降噪 声音增强等设置
    AudioOptimizerDialog  audio_optimizer_dlg_;
    audio_optimizer_dlg_.exec();
}

void HomeWindow::on_recordSetting()
{
    RecordSettingDialog  record_setting_dlg;
    record_setting_dlg.exec();
}

void HomeWindow::on_liveSetting()
{
    LiveSettingDialog live_setting_dlg;
    live_setting_dlg.exec();
}

void HomeWindow::on_startOrPauseBtn_clicked()
{
    if(!push_work_) {
        //加载rtmp串流地址
        QString url;
        GlobalHelper::GetDefaultRtmpUrl(url);
        // 加载rtmp串流密匙
        QString key;
        GlobalHelper::GetDefaultRtmpKey(key);
        QString url_key =  url + key;
        start(url_key.toStdString());
    } else {
        if(business_type_ == 1) {       // 单纯的录播才运行暂停和恢复
            // 判断暂停 继续的问题
            bool pause = push_work_->GetPause();
            pause = !pause; // 反转
            push_work_->SetPause(pause);
            if(pause) {
                ui->startOrPauseBtn->setText("继续");
            } else {
                ui->startOrPauseBtn->setText("暂停");
            }
        } else {
            emit sig_showTips(Toast::WARN, "只有单纯的录制业务才允许暂停/继续");
        }
    }
}

void HomeWindow::on_stopBtn_clicked()
{
    if(push_work_) {
        stop();
    }
}

void HomeWindow::on_showTips(Toast::Level leve, QString tips)
{
    Toast::instance().show(leve, tips);
}

void HomeWindow::on_businessType()
{
    //    LOG(INFO) << "on_businessType " << ui->typeGroupBox->ch;
}

void HomeWindow::on_typeGroupBox_clicked()
{
}

void HomeWindow::on_typeGroupBox_toggled(bool arg1)
{
    LOG(INFO) << "on_businessType " << arg1;
}

void HomeWindow::on_fileRadioBtn_toggled(bool checked)
{
    // 目前不支持本地文件推流直播
}

void HomeWindow::on_liveRadioButton_clicked(bool checked)
{
    LOG(INFO) << "on_liveRadioButton_clicked " << checked;
    enable_rtmp_live_ = checked;
    business_type_ = 0; // 录制推流，是否录制到本地由enable_record_决定
    if(ui->checkBoxRecord->isChecked()) {
        enable_record_ = true;
    }
    GlobalHelper::SaveBusinessesType(business_type_);
}

void HomeWindow::on_recRadioBtn_clicked(bool checked)
{
    LOG(INFO) << "on_recRadioBtn_clicked " << checked;
    enable_record_ = checked;
    if(enable_record_) {
        enable_rtmp_live_ = false;  //如果选中单纯录制则不能推流
    }
    if(ui->checkBoxRecord->isChecked()) {
        enable_record_ = true;      // 只要该按钮勾选则允许录制
    }
    business_type_ = 1; //单纯录制到本地
    GlobalHelper::SaveBusinessesType(business_type_);
}

void HomeWindow::on_checkBoxRecord_clicked(bool checked)
{
    if(checked) {
        GlobalHelper::SaveLiveRecord(1);
    } else {
        GlobalHelper::SaveLiveRecord(0);
    }
}

void HomeWindow::on_updateTime(long millisecond)
{
    do_updateTime(millisecond);
}

void HomeWindow::on_timeOut()
{
    if(push_work_) {
        // 读取录制时间 然后触发触发信号
        int64_t time =  push_work_->GetTime();
        emit sig_updateTime(time);
    }
}

// 打开保存录制文件的目录
void HomeWindow::on_openRecordDir_clicked()
{
    QString file_dir_path;
    GlobalHelper::GetFileDir(file_dir_path);
    QString path = QString("file:///") + file_dir_path;
    bool is_open = QDesktopServices::openUrl(QUrl(path, QUrl::TolerantMode));
    LOG(INFO) << "file_dir_path open? -> " << is_open;
}
